home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / keys.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  15KB  |  760 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "quakedef.h"
  21.  
  22. /*
  23.  
  24. key up events are sent even if in console mode
  25.  
  26. */
  27.  
  28.  
  29. #define        MAXCMDLINE    256
  30. char    key_lines[32][MAXCMDLINE];
  31. int        key_linepos;
  32. int        shift_down=false;
  33. int        key_lastpress;
  34.  
  35. int        edit_line=0;
  36. int        history_line=0;
  37.  
  38. keydest_t    key_dest;
  39.  
  40. int        key_count;            // incremented every key event
  41.  
  42. char    *keybindings[256];
  43. qboolean    consolekeys[256];    // if true, can't be rebound while in console
  44. qboolean    menubound[256];    // if true, can't be rebound while in menu
  45. int        keyshift[256];        // key to map to if shift held down in console
  46. int        key_repeats[256];    // if > 1, it is autorepeating
  47. qboolean    keydown[256];
  48.  
  49. typedef struct
  50. {
  51.     char    *name;
  52.     int        keynum;
  53. } keyname_t;
  54.  
  55. keyname_t keynames[] =
  56. {
  57.     {"TAB", K_TAB},
  58.     {"ENTER", K_ENTER},
  59.     {"ESCAPE", K_ESCAPE},
  60.     {"SPACE", K_SPACE},
  61.     {"BACKSPACE", K_BACKSPACE},
  62.     {"UPARROW", K_UPARROW},
  63.     {"DOWNARROW", K_DOWNARROW},
  64.     {"LEFTARROW", K_LEFTARROW},
  65.     {"RIGHTARROW", K_RIGHTARROW},
  66.  
  67.     {"ALT", K_ALT},
  68.     {"CTRL", K_CTRL},
  69.     {"SHIFT", K_SHIFT},
  70.     
  71.     {"F1", K_F1},
  72.     {"F2", K_F2},
  73.     {"F3", K_F3},
  74.     {"F4", K_F4},
  75.     {"F5", K_F5},
  76.     {"F6", K_F6},
  77.     {"F7", K_F7},
  78.     {"F8", K_F8},
  79.     {"F9", K_F9},
  80.     {"F10", K_F10},
  81.     {"F11", K_F11},
  82.     {"F12", K_F12},
  83.  
  84.     {"INS", K_INS},
  85.     {"DEL", K_DEL},
  86.     {"PGDN", K_PGDN},
  87.     {"PGUP", K_PGUP},
  88.     {"HOME", K_HOME},
  89.     {"END", K_END},
  90.  
  91.     {"MOUSE1", K_MOUSE1},
  92.     {"MOUSE2", K_MOUSE2},
  93.     {"MOUSE3", K_MOUSE3},
  94.  
  95.     {"JOY1", K_JOY1},
  96.     {"JOY2", K_JOY2},
  97.     {"JOY3", K_JOY3},
  98.     {"JOY4", K_JOY4},
  99.  
  100.     {"AUX1", K_AUX1},
  101.     {"AUX2", K_AUX2},
  102.     {"AUX3", K_AUX3},
  103.     {"AUX4", K_AUX4},
  104.     {"AUX5", K_AUX5},
  105.     {"AUX6", K_AUX6},
  106.     {"AUX7", K_AUX7},
  107.     {"AUX8", K_AUX8},
  108.     {"AUX9", K_AUX9},
  109.     {"AUX10", K_AUX10},
  110.     {"AUX11", K_AUX11},
  111.     {"AUX12", K_AUX12},
  112.     {"AUX13", K_AUX13},
  113.     {"AUX14", K_AUX14},
  114.     {"AUX15", K_AUX15},
  115.     {"AUX16", K_AUX16},
  116.     {"AUX17", K_AUX17},
  117.     {"AUX18", K_AUX18},
  118.     {"AUX19", K_AUX19},
  119.     {"AUX20", K_AUX20},
  120.     {"AUX21", K_AUX21},
  121.     {"AUX22", K_AUX22},
  122.     {"AUX23", K_AUX23},
  123.     {"AUX24", K_AUX24},
  124.     {"AUX25", K_AUX25},
  125.     {"AUX26", K_AUX26},
  126.     {"AUX27", K_AUX27},
  127.     {"AUX28", K_AUX28},
  128.     {"AUX29", K_AUX29},
  129.     {"AUX30", K_AUX30},
  130.     {"AUX31", K_AUX31},
  131.     {"AUX32", K_AUX32},
  132.  
  133.     {"PAUSE", K_PAUSE},
  134.  
  135.     {"MWHEELUP", K_MWHEELUP},
  136.     {"MWHEELDOWN", K_MWHEELDOWN},
  137.  
  138.     {"SEMICOLON", ';'},    // because a raw semicolon seperates commands
  139.  
  140.     {NULL,0}
  141. };
  142.  
  143. /*
  144. ==============================================================================
  145.  
  146.             LINE TYPING INTO THE CONSOLE
  147.  
  148. ==============================================================================
  149. */
  150.  
  151.  
  152. /*
  153. ====================
  154. Key_Console
  155.  
  156. Interactive line editing and console scrollback
  157. ====================
  158. */
  159. void Key_Console (int key)
  160. {
  161.     char    *cmd;
  162.     
  163.     if (key == K_ENTER)
  164.     {
  165.         Cbuf_AddText (key_lines[edit_line]+1);    // skip the >
  166.         Cbuf_AddText ("\n");
  167.         Con_Printf ("%s\n",key_lines[edit_line]);
  168.         edit_line = (edit_line + 1) & 31;
  169.         history_line = edit_line;
  170.         key_lines[edit_line][0] = ']';
  171.         key_linepos = 1;
  172.         if (cls.state == ca_disconnected)
  173.             SCR_UpdateScreen ();    // force an update, because the command
  174.                                     // may take some time
  175.         return;
  176.     }
  177.  
  178.     if (key == K_TAB)
  179.     {    // command completion
  180.         cmd = Cmd_CompleteCommand (key_lines[edit_line]+1);
  181.         if (!cmd)
  182.             cmd = Cvar_CompleteVariable (key_lines[edit_line]+1);
  183.         if (cmd)
  184.         {
  185.             Q_strcpy (key_lines[edit_line]+1, cmd);
  186.             key_linepos = Q_strlen(cmd)+1;
  187.             key_lines[edit_line][key_linepos] = ' ';
  188.             key_linepos++;
  189.             key_lines[edit_line][key_linepos] = 0;
  190.             return;
  191.         }
  192.     }
  193.     
  194.     if (key == K_BACKSPACE || key == K_LEFTARROW)
  195.     {
  196.         if (key_linepos > 1)
  197.             key_linepos--;
  198.         return;
  199.     }
  200.  
  201.     if (key == K_UPARROW)
  202.     {
  203.         do
  204.         {
  205.             history_line = (history_line - 1) & 31;
  206.         } while (history_line != edit_line
  207.                 && !key_lines[history_line][1]);
  208.         if (history_line == edit_line)
  209.             history_line = (edit_line+1)&31;
  210.         Q_strcpy(key_lines[edit_line], key_lines[history_line]);
  211.         key_linepos = Q_strlen(key_lines[edit_line]);
  212.         return;
  213.     }
  214.  
  215.     if (key == K_DOWNARROW)
  216.     {
  217.         if (history_line == edit_line) return;
  218.         do
  219.         {
  220.             history_line = (history_line + 1) & 31;
  221.         }
  222.         while (history_line != edit_line
  223.             && !key_lines[history_line][1]);
  224.         if (history_line == edit_line)
  225.         {
  226.             key_lines[edit_line][0] = ']';
  227.             key_linepos = 1;
  228.         }
  229.         else
  230.         {
  231.             Q_strcpy(key_lines[edit_line], key_lines[history_line]);
  232.             key_linepos = Q_strlen(key_lines[edit_line]);
  233.         }
  234.         return;
  235.     }
  236.  
  237.     if (key == K_PGUP || key==K_MWHEELUP)
  238.     {
  239.         con_backscroll += 2;
  240.         if (con_backscroll > con_totallines - (vid.height>>3) - 1)
  241.             con_backscroll = con_totallines - (vid.height>>3) - 1;
  242.         return;
  243.     }
  244.  
  245.     if (key == K_PGDN || key==K_MWHEELDOWN)
  246.     {
  247.         con_backscroll -= 2;
  248.         if (con_backscroll < 0)
  249.             con_backscroll = 0;
  250.         return;
  251.     }
  252.  
  253.     if (key == K_HOME)
  254.     {
  255.         con_backscroll = con_totallines - (vid.height>>3) - 1;
  256.         return;
  257.     }
  258.  
  259.     if (key == K_END)
  260.     {
  261.         con_backscroll = 0;
  262.         return;
  263.     }
  264.     
  265.     if (key < 32 || key > 127)
  266.         return;    // non printable
  267.         
  268.     if (key_linepos < MAXCMDLINE-1)
  269.     {
  270.         key_lines[edit_line][key_linepos] = key;
  271.         key_linepos++;
  272.         key_lines[edit_line][key_linepos] = 0;
  273.     }
  274.  
  275. }
  276.  
  277. //============================================================================
  278.  
  279. char chat_buffer[32];
  280. qboolean team_message = false;
  281.  
  282. void Key_Message (int key)
  283. {
  284.     static int chat_bufferlen = 0;
  285.  
  286.     if (key == K_ENTER)
  287.     {
  288.         if (team_message)
  289.             Cbuf_AddText ("say_team \"");
  290.         else
  291.             Cbuf_AddText ("say \"");
  292.         Cbuf_AddText(chat_buffer);
  293.         Cbuf_AddText("\"\n");
  294.  
  295.         key_dest = key_game;
  296.         chat_bufferlen = 0;
  297.         chat_buffer[0] = 0;
  298.         return;
  299.     }
  300.  
  301.     if (key == K_ESCAPE)
  302.     {
  303.         key_dest = key_game;
  304.         chat_bufferlen = 0;
  305.         chat_buffer[0] = 0;
  306.         return;
  307.     }
  308.  
  309.     if (key < 32 || key > 127)
  310.         return;    // non printable
  311.  
  312.     if (key == K_BACKSPACE)
  313.     {
  314.         if (chat_bufferlen)
  315.         {
  316.             chat_bufferlen--;
  317.             chat_buffer[chat_bufferlen] = 0;
  318.         }
  319.         return;
  320.     }
  321.  
  322.     if (chat_bufferlen == 31)
  323.         return; // all full
  324.  
  325.     chat_buffer[chat_bufferlen++] = key;
  326.     chat_buffer[chat_bufferlen] = 0;
  327. }
  328.  
  329. //============================================================================
  330.  
  331.  
  332. /*
  333. ===================
  334. Key_StringToKeynum
  335.  
  336. Returns a key number to be used to index keybindings[] by looking at
  337. the given string.  Single ascii characters return themselves, while
  338. the K_* names are matched up.
  339. ===================
  340. */
  341. int Key_StringToKeynum (char *str)
  342. {
  343.     keyname_t    *kn;
  344.     
  345.     if (!str || !str[0])
  346.         return -1;
  347.     if (!str[1])
  348.         return str[0];
  349.  
  350.     for (kn=keynames ; kn->name ; kn++)
  351.     {
  352.         if (!Q_strcasecmp(str,kn->name))
  353.             return kn->keynum;
  354.     }
  355.     return -1;
  356. }
  357.  
  358. /*
  359. ===================
  360. Key_KeynumToString
  361.  
  362. Returns a string (either a single ascii char, or a K_* name) for the
  363. given keynum.
  364. FIXME: handle quote special (general escape sequence?)
  365. ===================
  366. */
  367. char *Key_KeynumToString (int keynum)
  368. {
  369.     keyname_t    *kn;    
  370.     static    char    tinystr[2];
  371.     
  372.     if (keynum == -1)
  373.         return "<KEY NOT FOUND>";
  374.     if (keynum > 32 && keynum < 127)
  375.     {    // printable ascii
  376.         tinystr[0] = keynum;
  377.         tinystr[1] = 0;
  378.         return tinystr;
  379.     }
  380.     
  381.     for (kn=keynames ; kn->name ; kn++)
  382.         if (keynum == kn->keynum)
  383.             return kn->name;
  384.  
  385.     return "<UNKNOWN KEYNUM>";
  386. }
  387.  
  388.  
  389. /*
  390. ===================
  391. Key_SetBinding
  392. ===================
  393. */
  394. void Key_SetBinding (int keynum, char *binding)
  395. {
  396.     char    *new;
  397.     int        l;
  398.             
  399.     if (keynum == -1)
  400.         return;
  401.  
  402. // free old bindings
  403.     if (keybindings[keynum])
  404.     {
  405.         Z_Free (keybindings[keynum]);
  406.         keybindings[keynum] = NULL;
  407.     }
  408.             
  409. // allocate memory for new binding
  410.     l = Q_strlen (binding);    
  411.     new = Z_Malloc (l+1);
  412.     Q_strcpy (new, binding);
  413.     new[l] = 0;
  414.     keybindings[keynum] = new;    
  415. }
  416.  
  417. /*
  418. ===================
  419. Key_Unbind_f
  420. ===================
  421. */
  422. void Key_Unbind_f (void)
  423. {
  424.     int        b;
  425.  
  426.     if (Cmd_Argc() != 2)
  427.     {
  428.         Con_Printf ("unbind <key> : remove commands from a key\n");
  429.         return;
  430.     }
  431.     
  432.     b = Key_StringToKeynum (Cmd_Argv(1));
  433.     if (b==-1)
  434.     {
  435.         Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  436.         return;
  437.     }
  438.  
  439.     Key_SetBinding (b, "");
  440. }
  441.  
  442. void Key_Unbindall_f (void)
  443. {
  444.     int        i;
  445.     
  446.     for (i=0 ; i<256 ; i++)
  447.         if (keybindings[i])
  448.             Key_SetBinding (i, "");
  449. }
  450.  
  451.  
  452. /*
  453. ===================
  454. Key_Bind_f
  455. ===================
  456. */
  457. void Key_Bind_f (void)
  458. {
  459.     int            i, c, b;
  460.     char        cmd[1024];
  461.     
  462.     c = Cmd_Argc();
  463.  
  464.     if (c != 2 && c != 3)
  465.     {
  466.         Con_Printf ("bind <key> [command] : attach a command to a key\n");
  467.         return;
  468.     }
  469.     b = Key_StringToKeynum (Cmd_Argv(1));
  470.     if (b==-1)
  471.     {
  472.         Con_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  473.         return;
  474.     }
  475.  
  476.     if (c == 2)
  477.     {
  478.         if (keybindings[b])
  479.             Con_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
  480.         else
  481.             Con_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
  482.         return;
  483.     }
  484.     
  485. // copy the rest of the command line
  486.     cmd[0] = 0;        // start out with a null string
  487.     for (i=2 ; i< c ; i++)
  488.     {
  489.         if (i > 2)
  490.             strcat (cmd, " ");
  491.         strcat (cmd, Cmd_Argv(i));
  492.     }
  493.  
  494.     Key_SetBinding (b, cmd);
  495. }
  496.  
  497. /*
  498. ============
  499. Key_WriteBindings
  500.  
  501. Writes lines containing "bind key value"
  502. ============
  503. */
  504. void Key_WriteBindings (FILE *f)
  505. {
  506.     int        i;
  507.  
  508.     for (i=0 ; i<256 ; i++)
  509.         if (keybindings[i])
  510.             if (*keybindings[i])
  511.                 fprintf (f, "bind \"%s\" \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
  512. }
  513.  
  514.  
  515. /*
  516. ===================
  517. Key_Init
  518. ===================
  519. */
  520. void Key_Init (void)
  521. {
  522.     int        i;
  523.  
  524.     for (i=0 ; i<32 ; i++)
  525.     {
  526.         key_lines[i][0] = ']';
  527.         key_lines[i][1] = 0;
  528.     }
  529.     key_linepos = 1;
  530.     
  531. //
  532. // init ascii characters in console mode
  533. //
  534.     for (i=32 ; i<128 ; i++)
  535.         consolekeys[i] = true;
  536.     consolekeys[K_ENTER] = true;
  537.     consolekeys[K_TAB] = true;
  538.     consolekeys[K_LEFTARROW] = true;
  539.     consolekeys[K_RIGHTARROW] = true;
  540.     consolekeys[K_UPARROW] = true;
  541.     consolekeys[K_DOWNARROW] = true;
  542.     consolekeys[K_BACKSPACE] = true;
  543.     consolekeys[K_PGUP] = true;
  544.     consolekeys[K_PGDN] = true;
  545.     consolekeys[K_SHIFT] = true;
  546.     consolekeys[K_MWHEELUP] = true;
  547.     consolekeys[K_MWHEELDOWN] = true;
  548.     consolekeys['`'] = false;
  549.     consolekeys['~'] = false;
  550.  
  551.     for (i=0 ; i<256 ; i++)
  552.         keyshift[i] = i;
  553.     for (i='a' ; i<='z' ; i++)
  554.         keyshift[i] = i - 'a' + 'A';
  555.     keyshift['1'] = '!';
  556.     keyshift['2'] = '@';
  557.     keyshift['3'] = '#';
  558.     keyshift['4'] = '$';
  559.     keyshift['5'] = '%';
  560.     keyshift['6'] = '^';
  561.     keyshift['7'] = '&';
  562.     keyshift['8'] = '*';
  563.     keyshift['9'] = '(';
  564.     keyshift['0'] = ')';
  565.     keyshift['-'] = '_';
  566.     keyshift['='] = '+';
  567.     keyshift[','] = '<';
  568.     keyshift['.'] = '>';
  569.     keyshift['/'] = '?';
  570.     keyshift[';'] = ':';
  571.     keyshift['\''] = '"';
  572.     keyshift['['] = '{';
  573.     keyshift[']'] = '}';
  574.     keyshift['`'] = '~';
  575.     keyshift['\\'] = '|';
  576.  
  577.     menubound[K_ESCAPE] = true;
  578.     for (i=0 ; i<12 ; i++)
  579.         menubound[K_F1+i] = true;
  580.  
  581. //
  582. // register our functions
  583. //
  584.     Cmd_AddCommand ("bind",Key_Bind_f);
  585.     Cmd_AddCommand ("unbind",Key_Unbind_f);
  586.     Cmd_AddCommand ("unbindall",Key_Unbindall_f);
  587.  
  588.  
  589. }
  590.  
  591. /*
  592. ===================
  593. Key_Event
  594.  
  595. Called by the system between frames for both key up and key down events
  596. Should NOT be called during an interrupt!
  597. ===================
  598. */
  599. void Key_Event (int key, qboolean down)
  600. {
  601.     char    *kb;
  602.     char    cmd[1024];
  603.  
  604.     keydown[key] = down;
  605.  
  606.     if (!down)
  607.         key_repeats[key] = 0;
  608.  
  609.     key_lastpress = key;
  610.     key_count++;
  611.     if (key_count <= 0)
  612.     {
  613.         return;        // just catching keys for Con_NotifyBox
  614.     }
  615.  
  616. // update auto-repeat status
  617.     if (down)
  618.     {
  619.         key_repeats[key]++;
  620.         if (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)
  621.         {
  622.             return;    // ignore most autorepeats
  623.         }
  624.             
  625.         if (key >= 200 && !keybindings[key])
  626.             Con_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
  627.     }
  628.  
  629.     if (key == K_SHIFT)
  630.         shift_down = down;
  631.  
  632. //
  633. // handle escape specialy, so the user can never unbind it
  634. //
  635.     if (key == K_ESCAPE)
  636.     {
  637.         if (!down)
  638.             return;
  639.         switch (key_dest)
  640.         {
  641.         case key_message:
  642.             Key_Message (key);
  643.             break;
  644.         case key_menu:
  645.             M_Keydown (key);
  646.             break;
  647.         case key_game:
  648.         case key_console:
  649.             M_ToggleMenu_f ();
  650.             break;
  651.         default:
  652.             Sys_Error ("Bad key_dest");
  653.         }
  654.         return;
  655.     }
  656.  
  657. //
  658. // key up events only generate commands if the game key binding is
  659. // a button command (leading + sign).  These will occur even in console mode,
  660. // to keep the character from continuing an action started before a console
  661. // switch.  Button commands include the kenum as a parameter, so multiple
  662. // downs can be matched with ups
  663. //
  664.     if (!down)
  665.     {
  666.         kb = keybindings[key];
  667.         if (kb && kb[0] == '+')
  668.         {
  669.             sprintf (cmd, "-%s %i\n", kb+1, key);
  670.             Cbuf_AddText (cmd);
  671.         }
  672.         if (keyshift[key] != key)
  673.         {
  674.             kb = keybindings[keyshift[key]];
  675.             if (kb && kb[0] == '+')
  676.             {
  677.                 sprintf (cmd, "-%s %i\n", kb+1, key);
  678.                 Cbuf_AddText (cmd);
  679.             }
  680.         }
  681.         return;
  682.     }
  683.  
  684. //
  685. // during demo playback, most keys bring up the main menu
  686. //
  687.     if (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)
  688.     {
  689.         M_ToggleMenu_f ();
  690.         return;
  691.     }
  692.  
  693. //
  694. // if not a consolekey, send to the interpreter no matter what mode is
  695. //
  696.     if ( (key_dest == key_menu && menubound[key])
  697.     || (key_dest == key_console && !consolekeys[key])
  698.     || (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )
  699.     {
  700.         kb = keybindings[key];
  701.         if (kb)
  702.         {
  703.             if (kb[0] == '+')
  704.             {    // button commands add keynum as a parm
  705.                 sprintf (cmd, "%s %i\n", kb, key);
  706.                 Cbuf_AddText (cmd);
  707.             }
  708.             else
  709.             {
  710.                 Cbuf_AddText (kb);
  711.                 Cbuf_AddText ("\n");
  712.             }
  713.         }
  714.         return;
  715.     }
  716.  
  717.     if (!down)
  718.         return;        // other systems only care about key down events
  719.  
  720.     if (shift_down)
  721.     {
  722.         key = keyshift[key];
  723.     }
  724.  
  725.     switch (key_dest)
  726.     {
  727.     case key_message:
  728.         Key_Message (key);
  729.         break;
  730.     case key_menu:
  731.         M_Keydown (key);
  732.         break;
  733.  
  734.     case key_game:
  735.     case key_console:
  736.         Key_Console (key);
  737.         break;
  738.     default:
  739.         Sys_Error ("Bad key_dest");
  740.     }
  741. }
  742.  
  743.  
  744. /*
  745. ===================
  746. Key_ClearStates
  747. ===================
  748. */
  749. void Key_ClearStates (void)
  750. {
  751.     int        i;
  752.  
  753.     for (i=0 ; i<256 ; i++)
  754.     {
  755.         keydown[i] = false;
  756.         key_repeats[i] = 0;
  757.     }
  758. }
  759.  
  760.